import { PrismaClient } from '@prisma/client';
import { priceService } from './priceService';

const prisma = new PrismaClient();

/**
 * 质押收益结算服务
 * 每日自动计算并发放质押收益
 */
class SettlementService {
  /**
   * 执行每日结算
   * 为所有有质押本金的用户计算并发放每日收益
   */
  async dailySettlement(): Promise<{
    success: boolean;
    settledUsers: number;
    totalRewards: number;
    errors: string[];
  }> {
    const errors: string[] = [];
    let settledUsers = 0;
    let totalRewardsNear = 0;

    try {
      // 获取当前NEAR价格
      const nearPrice = await priceService.getNearPrice();
      const today = new Date();
      today.setHours(0, 0, 0, 0);

      // 获取所有有质押本金的用户
      const stakingUsers = await prisma.userStaking.findMany({
        where: {
          stakedAmount: {
            gt: 0
          }
        },
        include: {
          user: true
        }
      });

      console.log(`[정산] 일일 정산을 시작합니다. 대상 사용자 수: ${stakingUsers.length}명`);

      for (const staking of stakingUsers) {
        try {
          const stakedAmount = Number(staking.stakedAmount);
          const lockedAmount = Number(staking.lockedAmount || 0);
          const dailyRate = Number(staking.dailyRewardRate);

          // 计算每日收益（质押本金 + 锁定金额） * 日收益率
          const totalStakingBase = stakedAmount + lockedAmount;
          const dailyRewardNear = totalStakingBase * dailyRate;
          const dailyRewardKrw = dailyRewardNear * nearPrice;

          // 使用事务同时更新质押收益和用户余额
          await prisma.$transaction(async (tx) => {
            // 1. 更新累计质押收益NEAR（历史统计，只增不减）
            await tx.userStaking.update({
              where: { id: staking.id },
              data: {
                totalRewardsNear: Number(staking.totalRewardsNear) + dailyRewardNear,
                availableRewards: {
                  increment: dailyRewardNear
                },
                lastSettlementDate: today
              }
            });

            // 2. 更新用户余额（收益KRW转入可用余额）
            await tx.userBalance.upsert({
              where: { userId: staking.userId },
              update: {
                balance: { increment: dailyRewardKrw },
                total: { increment: dailyRewardKrw }
              },
              create: {
                userId: staking.userId,
                balance: dailyRewardKrw,
                frozen: 0,
                total: dailyRewardKrw
              }
            });
          });

          // 记录结算日志
          await prisma.stakingSettlement.create({
            data: {
              userId: staking.userId,
              stakedAmount,
              dailyRewardRate: dailyRate,
              rewardNear: dailyRewardNear,
              rewardKrw: dailyRewardKrw,
              nearPrice,
              settlementDate: today
            }
          });

          settledUsers++;
          totalRewardsNear += dailyRewardNear;

          console.log(`[정산] 사용자 ${staking.userId} 정산 완료: ${dailyRewardNear.toFixed(4)} NEAR`);
        } catch (userError) {
          const errorMsg = `사용자 ${staking.userId} 정산 실패: ${userError}`;
          console.error(`[정산] ${errorMsg}`);
          errors.push(errorMsg);
        }
      }

      console.log(`[정산] 일일 정산 완료: ${settledUsers}명, 총 보상 ${totalRewardsNear.toFixed(4)} NEAR`);

      return {
        success: true,
        settledUsers,
        totalRewards: totalRewardsNear,
        errors
      };
    } catch (error) {
      console.error('[정산] 일일 정산에 실패했습니다.:', error);
      return {
        success: false,
        settledUsers,
        totalRewards: totalRewardsNear,
        errors: [...errors, `시스템 오류: ${error}`]
      };
    }
  }

  /**
   * 为单个用户执行结算（管理员手动触发）
   */
  async settleUser(userId: number): Promise<{
    success: boolean;
    rewardNear: number;
    rewardKrw: number;
    message: string;
  }> {
    try {
      const staking = await prisma.userStaking.findFirst({
        where: { userId }
      });

      if (!staking) {
        return {
          success: false,
          rewardNear: 0,
          rewardKrw: 0,
          message: '사용자에게 스테이킹 기록이 없습니다.'
        };
      }

      const stakedAmount = Number(staking.stakedAmount);
      if (stakedAmount <= 0) {
        return {
          success: false,
          rewardNear: 0,
          rewardKrw: 0,
          message: '사용자에게 스테이킹 원금이 없습니다.'
        };
      }

      const nearPrice = await priceService.getNearPrice();
      const lockedAmount = Number(staking.lockedAmount || 0);
      const dailyRate = Number(staking.dailyRewardRate);

      // 计算每日收益
      const totalStakingBase = stakedAmount + lockedAmount;
      const dailyRewardNear = totalStakingBase * dailyRate;
      const dailyRewardKrw = dailyRewardNear * nearPrice;

      // 使用事务同时更新质押收益和用户余额
        await prisma.$transaction(async (tx) => {
          // 1. 更新累计质押收益NEAR（历史统计，只增不减）
          await tx.userStaking.update({
            where: { id: staking.id },
            data: {
              totalRewardsNear: Number(staking.totalRewardsNear) + dailyRewardNear,
              availableRewards: {
                increment: dailyRewardNear
              },
              lastSettlementDate: new Date()
            }
          });

        // 2. 更新用户余额（收益KRW转入可用余额）
        await tx.userBalance.upsert({
          where: { userId },
          update: {
            balance: { increment: dailyRewardKrw },
            total: { increment: dailyRewardKrw }
          },
          create: {
            userId,
            balance: dailyRewardKrw,
            frozen: 0,
            total: dailyRewardKrw
          }
        });
      });

      // 记录结算日志
      await prisma.stakingSettlement.create({
        data: {
          userId,
          stakedAmount,
          dailyRewardRate: dailyRate,
          rewardNear: dailyRewardNear,
          rewardKrw: dailyRewardKrw,
          nearPrice,
          settlementDate: new Date()
        }
      });

      return {
        success: true,
        rewardNear: dailyRewardNear,
        rewardKrw: dailyRewardKrw,
        message: '정산이 완료되었습니다.'
      };
    } catch (error) {
      console.error('사용자 정산에 실패했습니다.:', error);
      return {
        success: false,
        rewardNear: 0,
        rewardKrw: 0,
        message: `정산 실패: ${error}`
      };
    }
  }

  /**
   * 获取用户的结算历史
   */
  async getSettlementHistory(userId: number, limit: number = 30): Promise<any[]> {
    try {
      const history = await prisma.stakingSettlement.findMany({
        where: { userId },
        orderBy: { settlementDate: 'desc' },
        take: limit
      });

      return history.map(h => ({
        id: h.id,
        date: h.settlementDate,
        stakedAmount: Number(h.stakedAmount),
        dailyRate: Number(h.dailyRewardRate),
        rewardNear: Number(h.rewardNear),
        rewardKrw: Number(h.rewardKrw),
        nearPrice: Number(h.nearPrice)
      }));
    } catch (error) {
      console.error('정산 내역 조회에 실패했습니다.:', error);
      return [];
    }
  }
}

export const settlementService = new SettlementService();
